home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 501-525 / disk_525 / siod / slib.c < prev   
C/C++ Source or Header  |  1992-05-06  |  39KB  |  1,606 lines

  1. /* Scheme In One Defun, but in C this time.
  2.  
  3.  *                        COPYRIGHT (c) 1989 BY                             *
  4.  *        PARADIGM ASSOCIATES INCORPORATED, CAMBRIDGE, MASSACHUSETTS.       *
  5.  *               ALL RIGHTS RESERVED                              *
  6.  
  7. Permission to use, copy, modify, distribute and sell this software
  8. and its documentation for any purpose and without fee is hereby
  9. granted, provided that the above copyright notice appear in all copies
  10. and that both that copyright notice and this permission notice appear
  11. in supporting documentation, and that the name of Paradigm Associates
  12. Inc not be used in advertising or publicity pertaining to distribution
  13. of the software without specific, written prior permission.
  14.  
  15. PARADIGM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  16. ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  17. PARADIGM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  18. ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  19. WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  20. ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  21. SOFTWARE.
  22.  
  23. */
  24.  
  25. /*
  26.  
  27. gjc@paradigm.com
  28.  
  29. Paradigm Associates Inc          Phone: 617-492-6079
  30. 29 Putnam Ave, Suite 6
  31. Cambridge, MA 02138
  32.  
  33.  
  34.    Release 1.0: 24-APR-88
  35.    Release 1.1: 25-APR-88, added: macros, predicates, load. With additions by
  36.     Barak.Pearlmutter@DOGHEN.BOLTZ.CS.CMU.EDU: Full flonum recognizer,
  37.     cleaned up uses of NULL/0. Now distributed with siod.scm.
  38.    Release 1.2: 28-APR-88, name changes as requested by JAR@AI.AI.MIT.EDU,
  39.     plus some bug fixes.
  40.    Release 1.3: 1-MAY-88, changed env to use frames instead of alist.
  41.     define now works properly. vms specific function edit.
  42.    Release 1.4 20-NOV-89. Minor Cleanup and remodularization.
  43.     Now in 3 files, siod.h, slib.c, siod.c. Makes it easier to write your
  44.     own main loops. Some short-int changes for lightspeed C included.
  45.    Release 1.5 29-NOV-89. Added startup flag -g, select stop and copy
  46.     or mark-and-sweep garbage collection, which assumes that the stack/register
  47.     marking code is correct for your architecture. 
  48.    Release 2.0 1-DEC-89. Added repl_hooks, Catch, Throw. This is significantly
  49.     different enough (from 1.3) now that I'm calling it a major release.
  50.    Release 2.1 4-DEC-89. Small reader features, dot, backquote, comma.
  51.    Release 2.2 5-DEC-89. gc,read,print,eval, hooks for user defined datatypes.
  52.    Release 2.3 6-DEC-89. save_forms, obarray intern mechanism. comment char.
  53.    Release 2.3a......... minor speed-ups. i/o interrupt considerations.
  54.    Release 2.4 27-APR-90 gen_readr, for read-from-string.
  55.  
  56.   */
  57.  
  58. #include <stdio.h>
  59. #include <string.h>
  60. #include <ctype.h>
  61. #include <setjmp.h>
  62. #include <signal.h>
  63. #include <math.h>
  64. #ifdef vms
  65. #include <stdlib.h>
  66. #endif
  67.  
  68. #include "siod.h"
  69.  
  70. LISP heap_1,heap_2;
  71. LISP heap,heap_end,heap_org;
  72.  
  73. long heap_size = 5000;
  74. long old_heap_used;
  75. long which_heap;
  76. long gc_status_flag = 1;
  77. char *init_file = (char *) NULL;
  78. char tkbuffer[TKBUFFERN];
  79.  
  80. long gc_kind_copying = 1;
  81.  
  82. long gc_cells_allocated = 0;
  83. double gc_time_taken;
  84. LISP *stack_start_ptr;
  85. LISP freelist;
  86.  
  87. jmp_buf errjmp;
  88. long errjmp_ok = 0;
  89. long nointerrupt = 1;
  90. long interrupt_differed = 0;
  91.  
  92. LISP oblistvar = NIL;
  93. LISP truth = NIL;
  94. LISP eof_val = NIL;
  95. LISP sym_errobj = NIL;
  96. LISP sym_progn = NIL;
  97. LISP sym_lambda = NIL;
  98. LISP sym_quote = NIL;
  99. LISP sym_dot = NIL;
  100. LISP open_files = NIL;
  101. LISP unbound_marker = NIL;
  102.  
  103. LISP *obarray;
  104. long obarray_dim = 100;
  105.  
  106. struct catch_frame
  107. {LISP tag;
  108.  LISP retval;
  109.  jmp_buf cframe;
  110.  struct catch_frame *next;};
  111.  
  112. struct gc_protected
  113. {LISP *location;
  114.  long length;
  115.  struct gc_protected *next;};
  116.  
  117. struct catch_frame *catch_framep = (struct catch_frame *) NULL;
  118.  
  119.  
  120. process_cla(argc,argv,warnflag)
  121.  int argc,warnflag; char **argv;
  122. {int k;
  123.  for(k=1;k<argc;++k)
  124.    {if (strlen(argv[k])<2) continue;
  125.     if (argv[k][0] != '-')
  126.       {if (warnflag) printf("bad arg: %s\n",argv[k]);continue;}
  127.     switch(argv[k][1])
  128.       {case 'h':
  129.      heap_size = atol(&(argv[k][2])); break;
  130.        case 'o':
  131.      obarray_dim = atol(&(argv[k][2])); break;
  132.        case 'i':
  133.      init_file = &(argv[k][2]); break;
  134.        case 'g':
  135.      gc_kind_copying = atol(&(argv[k][2])); break;
  136.        default: if (warnflag) printf("bad arg: %s\n",argv[k]);}}}
  137.  
  138. print_welcome()
  139. {printf("Welcome to SIOD, Scheme In One Defun, Version 2.4\n");
  140.  printf("(C) Copyright 1988, 1989, 1990 Paradigm Associates Inc.\n");}
  141.  
  142. print_hs_1()
  143. {printf("heap_size = %ld cells, %ld bytes. GC is %s\n",
  144.         heap_size,heap_size*sizeof(struct obj),
  145.     (gc_kind_copying == 1) ? "stop and copy" : "mark and sweep");}
  146.  
  147. print_hs_2()
  148. {if (gc_kind_copying == 1)
  149.    printf("heap_1 at 0x%lX, heap_2 at 0x%lX\n",heap_1,heap_2);
  150.  else
  151.    printf("heap_1 at 0x%lX\n",heap_1);}
  152.  
  153. long no_interrupt(n)
  154.      long n;
  155. {long x;
  156.  x = nointerrupt;
  157.  nointerrupt = n;
  158.  if ((nointerrupt == 0) && (interrupt_differed == 1))
  159.    {interrupt_differed = 0;
  160.     err_ctrl_c();}
  161.  return(x);}
  162.  
  163.  
  164.  
  165. void handle_sigfpe(sig,code,scp)
  166.  long sig,code; struct sigcontext *scp;
  167. {signal(SIGFPE,handle_sigfpe);
  168.  err("floating point exception",NIL);}
  169.  
  170. void handle_sigint(sig,code,scp)
  171.  long sig,code; struct sigcontext *scp;
  172. {signal(SIGINT,handle_sigint);
  173.  if (nointerrupt == 1)
  174.    interrupt_differed = 1;
  175.  else
  176.    err_ctrl_c();}
  177.  
  178. err_ctrl_c()
  179. {err("control-c interrupt",NIL);}
  180.  
  181. LISP get_eof_val()
  182. {return(eof_val);}
  183.  
  184. repl_driver(want_sigint,want_init)
  185.      long want_sigint,want_init;
  186. {int k;
  187.  LISP stack_start;
  188.  stack_start_ptr = &stack_start;
  189.  k = setjmp(errjmp);
  190.  if (k == 2) return;
  191.  if (want_sigint) signal(SIGFPE,handle_sigfpe);
  192.  signal(SIGINT,handle_sigint);
  193.  close_open_files();
  194.  catch_framep = (struct catch_frame *) NULL;
  195.  errjmp_ok = 1;
  196.  interrupt_differed = 0;
  197.  nointerrupt = 0;
  198.  if (want_init && init_file && (k == 0)) vload(init_file,0);
  199.  repl();}
  200.  
  201. #ifdef unix
  202. #include <sys/types.h>
  203. #include <sys/times.h>
  204. struct tms time_buffer;
  205. double myruntime()
  206. {times(&time_buffer);
  207.  return(time_buffer.tms_utime/60.0);}
  208. #else
  209. #ifdef vms
  210. #include <time.h>
  211. double myruntime()
  212. {return(clock() * 1.0e-2);}
  213. #else
  214. double myruntime()
  215. {long x;
  216.  long time();
  217.  time(&x);
  218.  return((double) x);}
  219. #endif
  220. #endif
  221.  
  222.  
  223. void (*repl_puts)() = NULL;
  224. LISP (*repl_read)() = NULL;
  225. LISP (*repl_eval)() = NULL;
  226. void (*repl_print)() = NULL;
  227.  
  228. void set_repl_hooks(puts_f,read_f,eval_f,print_f)
  229.      void (*puts_f)();
  230.      LISP (*read_f)();
  231.      LISP (*eval_f)();
  232.      void (*print_f)();
  233. {repl_puts = puts_f;
  234.  repl_read = read_f;
  235.  repl_eval = eval_f;
  236.  repl_print = print_f;}
  237.  
  238. fput_st(f,st)
  239.      FILE *f;
  240.      char *st;
  241. {long flag;
  242.  flag = no_interrupt(1);
  243.  fprintf(f,"%s",st);
  244.  no_interrupt(flag);}
  245.  
  246. put_st(st)
  247.      char *st;
  248. {fput_st(stdout,st);}
  249.      
  250. grepl_puts(st)
  251.      char *st;
  252. {if (repl_puts == NULL)
  253.    put_st(st);
  254.  else
  255.    (*repl_puts)(st);}
  256.      
  257. repl() 
  258. {LISP x,cw;
  259.  double rt;
  260.  while(1)
  261.    {if ((gc_kind_copying == 1) && ((gc_status_flag) || heap >= heap_end))
  262.      {rt = myruntime();
  263.       gc_stop_and_copy();
  264.       sprintf(tkbuffer,
  265.           "GC took %g seconds, %ld compressed to %ld, %ld free\n",
  266.           myruntime()-rt,old_heap_used,heap-heap_org,heap_end-heap);
  267.       grepl_puts(tkbuffer);}
  268.     grepl_puts("> ");
  269.     if (repl_read == NULL) x = lread();
  270.     else x = (*repl_read)();
  271.     if EQ(x,eof_val) break;
  272.     rt = myruntime();
  273.     if (gc_kind_copying == 1)
  274.       cw = heap;
  275.     else
  276.       {gc_cells_allocated = 0;
  277.        gc_time_taken = 0.0;}
  278.     if (repl_eval == NULL) x = leval(x,NIL);
  279.     else x = (*repl_eval)();
  280.     if (gc_kind_copying == 1)
  281.       sprintf(tkbuffer,
  282.           "Evaluation took %g seconds %ld cons work\n",
  283.           myruntime()-rt,
  284.           heap-cw);
  285.     else
  286.       sprintf(tkbuffer,
  287.           "Evaluation took %g seconds (%g in gc) %ld cons work\n",
  288.           myruntime()-rt,
  289.           gc_time_taken,
  290.           gc_cells_allocated);
  291.     grepl_puts(tkbuffer);
  292.     if (repl_print == NULL) lprint(x);
  293.     else (*repl_print)(x);}}
  294.  
  295. err(message,x)
  296.  char *message; LISP x;
  297. {nointerrupt = 1;
  298.  if NNULLP(x) 
  299.     printf("ERROR: %s (see errobj)\n",message);
  300.   else printf("ERROR: %s\n",message);
  301.  if (errjmp_ok == 1) {setvar(sym_errobj,x,NIL); longjmp(errjmp,1);}
  302.  printf("FATAL ERROR DURING STARTUP OR CRITICAL CODE SECTION\n");
  303.  exit(1);}
  304.  
  305.  
  306. LISP lerr(message,x)
  307.      LISP message,x;
  308. {if NSYMBOLP(message) err("argument to error not a symbol",message);
  309.  err(PNAME(message),x);
  310.  return(NIL);}
  311.  
  312. void gc_fatal_error()
  313. {err("ran out of storage",NIL);}
  314.  
  315. #define NEWCELL(_into,_type)          \
  316. {if (gc_kind_copying == 1)            \
  317.    {if ((_into = heap) >= heap_end)   \
  318.       gc_fatal_error();               \
  319.     heap = _into+1;}                  \
  320.  else                                 \
  321.    {if NULLP(freelist)                \
  322.       gc_for_newcell();               \
  323.     _into = freelist;                 \
  324.     freelist = CDR(freelist);         \
  325.     ++gc_cells_allocated;}            \
  326.  (*_into).gc_mark = 0;                \
  327.  (*_into).type = _type;}
  328.  
  329. LISP newcell(type)
  330.      long type;
  331. {LISP z;
  332.  NEWCELL(z,type);
  333.  return(z);}
  334.  
  335. LISP cons(x,y)
  336.      LISP x,y;
  337. {LISP z;
  338.  NEWCELL(z,tc_cons);
  339.  CAR(z) = x;
  340.  CDR(z) = y;
  341.  return(z);}
  342.  
  343. LISP consp(x)
  344.      LISP x;
  345. {if CONSP(x) return(truth); else return(NIL);}
  346.  
  347. LISP car(x)
  348.      LISP x;
  349. {switch TYPE(x)
  350.    {case tc_nil:
  351.       return(NIL);
  352.     case tc_cons:
  353.       return(CAR(x));
  354.     default:
  355.       err("wta to car",x);}}
  356.  
  357. LISP cdr(x)
  358.      LISP x;
  359. {switch TYPE(x)
  360.    {case tc_nil:
  361.       return(NIL);
  362.     case tc_cons:
  363.       return(CDR(x));
  364.     default:
  365.       err("wta to cdr",x);}}
  366.  
  367.  
  368. LISP setcar(cell,value)
  369.      LISP cell, value;
  370. {if NCONSP(cell) err("wta to setcar",cell);
  371.  return(CAR(cell) = value);}
  372.  
  373. LISP setcdr(cell,value)
  374.      LISP cell, value;
  375. {if NCONSP(cell) err("wta to setcdr",cell);
  376.  return(CDR(cell) = value);}
  377.  
  378. LISP flocons(x)
  379.  double x;
  380. {LISP z;
  381.  NEWCELL(z,tc_flonum);
  382.  FLONM(z) = x;
  383.  return(z);}
  384.  
  385. LISP numberp(x)
  386.      LISP x;
  387. {if FLONUMP(x) return(truth); else return(NIL);}
  388.  
  389. LISP plus(x,y)
  390.      LISP x,y;
  391. {LISP z;
  392.  if NFLONUMP(x) err("wta(1st) to plus",x);
  393.  if NFLONUMP(y) err("wta(2nd) to plus",y);
  394.  NEWCELL(z,tc_flonum);
  395.  FLONM(z) = FLONM(x) + FLONM(y);
  396.  return(z);}
  397.  
  398. LISP ltimes(x,y)
  399.  LISP x,y;
  400. {LISP z;
  401.  if NFLONUMP(x) err("wta(1st) to times",x);
  402.  if NFLONUMP(y) err("wta(2nd) to times",y);
  403.  NEWCELL(z,tc_flonum);
  404.  FLONM(z) = FLONM(x)*FLONM(y);
  405.  return(z);}
  406.  
  407. LISP difference(x,y)
  408.  LISP x,y;
  409. {LISP z;
  410.  if NFLONUMP(x) err("wta(1st) to difference",x);
  411.  if NFLONUMP(y) err("wta(2nd) to difference",y);
  412.  NEWCELL(z,tc_flonum);
  413.  FLONM(z) = FLONM(x) - FLONM(y);
  414.  return(z);}
  415.  
  416.  
  417. LISP quotient(x,y)
  418.  LISP x,y;
  419. {LISP z;
  420.  if NFLONUMP(x) err("wta(1st) to quotient",x);
  421.  if NFLONUMP(y) err("wta(2nd) to quotient",y);
  422.  NEWCELL(z,tc_flonum);
  423.  FLONM(z) = FLONM(x)/FLONM(y);
  424.  return(z);}
  425.  
  426. LISP greaterp(x,y)
  427.  LISP x,y;
  428. {if NFLONUMP(x) err("wta(1st) to greaterp",x);
  429.  if NFLONUMP(y) err("wta(2nd) to greaterp",y);
  430.  if (FLONM(x)>FLONM(y)) return(truth);
  431.  return(NIL);}
  432.  
  433. LISP lessp(x,y)
  434.  LISP x,y;
  435. {if NFLONUMP(x) err("wta(1st) to lessp",x);
  436.  if NFLONUMP(y) err("wta(2nd) to lessp",y);
  437.  if (FLONM(x)<FLONM(y)) return(truth);
  438.  return(NIL);}
  439.  
  440. LISP eq(x,y)
  441.  LISP x,y;
  442. {if EQ(x,y) return(truth); else return(NIL);}
  443.  
  444. LISP eql(x,y)
  445.  LISP x,y;
  446. {if EQ(x,y) return(truth); else 
  447.  if NFLONUMP(x) return(NIL); else
  448.  if NFLONUMP(y) return(NIL); else
  449.  if (FLONM(x) == FLONM(y)) return(truth);
  450.  return(NIL);}
  451.  
  452. LISP symcons(pname,vcell)
  453.  char *pname; LISP vcell;
  454. {LISP z;
  455.  NEWCELL(z,tc_symbol);
  456.  PNAME(z) = pname;
  457.  VCELL(z) = vcell;
  458.  return(z);}
  459.  
  460. LISP symbolp(x)
  461.      LISP x;
  462. {if SYMBOLP(x) return(truth); else return(NIL);}
  463.  
  464. LISP symbol_boundp(x,env)
  465.  LISP x,env;
  466. {LISP tmp;
  467.  if NSYMBOLP(x) err("not a symbol",x);
  468.  tmp = envlookup(x,env);
  469.  if NNULLP(tmp) return(truth);
  470.  if EQ(VCELL(x),unbound_marker) return(NIL); else return(truth);}
  471.  
  472. LISP symbol_value(x,env)
  473.  LISP x,env;
  474. {LISP tmp;
  475.  if NSYMBOLP(x) err("not a symbol",x);
  476.  tmp = envlookup(x,env);
  477.  if NNULLP(tmp) return(CAR(tmp));
  478.  tmp = VCELL(x);
  479.  if EQ(tmp,unbound_marker) err("unbound variable",x);
  480.  return(tmp);}
  481.  
  482. char * must_malloc(size)
  483.      unsigned long size;
  484. {char *tmp;
  485.  tmp = (char *) malloc(size);
  486.  if (tmp == (char *)NULL) err("failed to allocate storage from system",NIL);
  487.  return(tmp);}
  488.  
  489. LISP gen_intern(name,copyp)
  490.      char *name;
  491.      long copyp;
  492. {LISP l,sym,sl;
  493.  char *cname;
  494.  long hash,n,c,flag;
  495.  flag = no_interrupt(1);
  496.  if (obarray_dim > 1)
  497.    {hash = 0;
  498.     n = obarray_dim;
  499.     cname = name;
  500.     while(c = *cname++) hash = ((hash * 17) ^ c) % n;
  501.     sl = obarray[hash];}
  502.  else
  503.    sl = oblistvar;
  504.  for(l=sl;NNULLP(l);l=CDR(l))
  505.    if (strcmp(name,PNAME(CAR(l))) == 0)
  506.      {no_interrupt(flag);
  507.       return(CAR(l));}
  508.  if (copyp == 1)
  509.    {cname = must_malloc(strlen(name)+1);
  510.     strcpy(cname,name);}
  511.  else
  512.    cname = name;
  513.  sym = symcons(cname,unbound_marker);
  514.  if (obarray_dim > 1) obarray[hash] = cons(sym,sl);
  515.  oblistvar = cons(sym,oblistvar);
  516.  no_interrupt(flag);
  517.  return(sym);}
  518.  
  519. LISP cintern(name)
  520.  char *name;
  521. {return(gen_intern(name,0));}
  522.  
  523. LISP rintern(name)
  524.  char *name;
  525. {return(gen_intern(name,1));}
  526.  
  527. LISP subrcons(type,name,f)
  528.  long type; char *name; LISP (*f)();
  529. {LISP z;
  530.  NEWCELL(z,type);
  531.  (*z).storage_as.subr.name = name;
  532.  (*z).storage_as.subr.f = f;
  533.  return(z);}
  534.  
  535.  
  536. LISP closure(env,code)
  537.      LISP env,code;
  538. {LISP z;
  539.  NEWCELL(z,tc_closure);
  540.  (*z).storage_as.closure.env = env;
  541.  (*z).storage_as.closure.code = code;
  542.  return(z);}
  543.  
  544.  
  545. struct gc_protected *protected_registers = NULL;
  546.  
  547. void gc_protect(location)
  548.      LISP *location;
  549. {gc_protect_n(location,1);}
  550.  
  551. void gc_protect_n(location,n)
  552.      LISP *location;
  553.      long n;
  554. {struct gc_protected *reg;
  555.  reg = (struct gc_protected *) must_malloc(sizeof(struct gc_protected));
  556.  (*reg).location = location;
  557.  (*reg).length = n;
  558.  (*reg).next = protected_registers;
  559.   protected_registers = reg;}
  560.  
  561. void gc_protect_sym(location,st)
  562.      LISP *location;
  563.      char *st;
  564. {*location = cintern(st);
  565.  gc_protect(location);}
  566.  
  567. scan_registers()
  568. {struct gc_protected *reg;
  569.  LISP *location;
  570.  long j,n;
  571.  for(reg = protected_registers; reg; reg = (*reg).next)
  572.    {location = (*reg).location;
  573.     n = (*reg).length;
  574.     for(j=0;j<n;++j)
  575.       location[j] = gc_relocate(location[j]);}}
  576.  
  577. init_storage()
  578. {LISP ptr,next,end;
  579.  long j;
  580.  heap_1 = (LISP) must_malloc(sizeof(struct obj)*heap_size);
  581.  heap = heap_1;
  582.  which_heap = 1;
  583.  heap_org = heap;
  584.  heap_end = heap + heap_size;
  585.  if (gc_kind_copying == 1)
  586.    heap_2 = (LISP) must_malloc(sizeof(struct obj)*heap_size);
  587.  else
  588.    {ptr = heap_org;
  589.     end = heap_end;
  590.     while(1)
  591.       {(*ptr).type = tc_free_cell;
  592.        next = ptr + 1;
  593.        if (next < end)
  594.      {CDR(ptr) = next;
  595.       ptr = next;}
  596.        else
  597.      {CDR(ptr) = NIL;
  598.       break;}}
  599.     freelist = heap_org;}
  600.  gc_protect(&oblistvar);
  601.  if (obarray_dim > 1)
  602.    {obarray = (LISP *) must_malloc(sizeof(LISP) * obarray_dim);
  603.     for(j=0;j<obarray_dim;++j)
  604.       obarray[j] = NIL;
  605.     gc_protect_n(obarray,obarray_dim);}
  606.  unbound_marker = cons(cintern("**unbound-marker**"),NIL);
  607.  gc_protect(&unbound_marker);
  608.  eof_val = cons(cintern("eof"),NIL);
  609.  gc_protect(&eof_val);
  610.  gc_protect_sym(&truth,"t");
  611.  setvar(truth,truth,NIL);
  612.  setvar(cintern("nil"),NIL,NIL);
  613.  setvar(cintern("let"),cintern("let-internal-macro"),NIL);
  614.  gc_protect_sym(&sym_errobj,"errobj");
  615.  setvar(sym_errobj,NIL,NIL);
  616.  gc_protect_sym(&sym_progn,"begin");
  617.  gc_protect_sym(&sym_lambda,"lambda");
  618.  gc_protect_sym(&sym_quote,"quote");
  619.  gc_protect_sym(&sym_dot,".");
  620.  gc_protect(&open_files);}
  621.  
  622. void init_subr(name,type,fcn)
  623.  char *name; long type; LISP (*fcn)();
  624. {setvar(cintern(name),subrcons(type,name,fcn),NIL);}
  625.  
  626. LISP assq(x,alist)
  627.      LISP x,alist;
  628. {LISP l,tmp;
  629.  for(l=alist;CONSP(l);l=CDR(l))
  630.    {tmp = CAR(l);
  631.     if (CONSP(tmp) && EQ(CAR(tmp),x)) return(tmp);}
  632.  if EQ(l,NIL) return(NIL);
  633.  err("improper list to assq",alist);}
  634.  
  635. LISP (*user_gc_relocate)() = NULL;
  636. void (*user_gc_scan)() = NULL;
  637. LISP (*user_gc_mark)() = NULL;
  638. void (*user_gc_free)() = NULL;
  639.  
  640. void set_gc_hooks(rel,scan,mark,free,kind)
  641.      LISP (*rel)(),(*mark)();
  642.      void (*scan)(),(*free)();
  643.      long *kind;
  644. {user_gc_relocate = rel;
  645.  user_gc_scan = scan;
  646.  user_gc_mark = mark;
  647.  user_gc_free = free;
  648.  *kind = gc_kind_copying;}
  649.  
  650. LISP gc_relocate(x)
  651.      LISP x;
  652. {LISP new;
  653.  if EQ(x,NIL) return(NIL);
  654.  if ((*x).gc_mark == 1) return(CAR(x));
  655.  switch TYPE(x)
  656.    {case tc_flonum:
  657.     case tc_cons:
  658.     case tc_symbol:
  659.     case tc_closure:
  660.     case tc_subr_0:
  661.     case tc_subr_1:
  662.     case tc_subr_2:
  663.     case tc_subr_3:
  664.     case tc_lsubr:
  665.     case tc_fsubr:
  666.     case tc_msubr:
  667.       if ((new = heap) >= heap_end) gc_fatal_error();
  668.       heap = new+1;
  669.       memcpy(new,x,sizeof(struct obj));
  670.       break;
  671.     case tc_user_1:
  672.     case tc_user_2:
  673.     case tc_user_3:
  674.     case tc_user_4:
  675.     case tc_user_5:
  676.       if (user_gc_relocate != NULL)
  677.     {new = (*user_gc_relocate)(x);
  678.      break;}
  679.     default: err("BUG IN GARBAGE COLLECTOR gc_relocate",NIL);}
  680.  (*x).gc_mark = 1;
  681.  CAR(x) = new;
  682.  return(new);}
  683.  
  684. LISP get_newspace()
  685. {LISP newspace;
  686.  if (which_heap == 1)
  687.    {newspace = heap_2;
  688.     which_heap = 2;}
  689.  else
  690.    {newspace = heap_1;
  691.     which_heap = 1;}
  692.  heap = newspace;
  693.  heap_org = heap;
  694.  heap_end = heap + heap_size;
  695.  return(newspace);}
  696.  
  697. scan_newspace(newspace)
  698.      LISP newspace;
  699. {LISP ptr;
  700.  for(ptr=newspace; ptr < heap; ++ptr)
  701.    {switch TYPE(ptr)
  702.       {case tc_cons:
  703.        case tc_closure:
  704.      CAR(ptr) = gc_relocate(CAR(ptr));
  705.      CDR(ptr) = gc_relocate(CDR(ptr));
  706.      break;
  707.        case tc_symbol:
  708.      VCELL(ptr) = gc_relocate(VCELL(ptr));
  709.      break;
  710.        case tc_user_1:
  711.        case tc_user_2:
  712.        case tc_user_3:
  713.        case tc_user_4:
  714.        case tc_user_5:
  715.      if (user_gc_scan != NULL) (*user_gc_scan)(ptr);
  716.      break;
  717.        default:
  718.      break;}}}
  719.       
  720. gc_stop_and_copy()
  721. {LISP newspace;
  722.  long flag;
  723.  flag = no_interrupt(1);
  724.  errjmp_ok = 0;
  725.  old_heap_used = heap - heap_org;
  726.  newspace = get_newspace();
  727.  scan_registers();
  728.  scan_newspace(newspace);
  729.  errjmp_ok = 1;
  730.  no_interrupt(flag);}
  731.  
  732. gc_for_newcell()
  733. {long flag;
  734.  if (errjmp_ok == 0) gc_fatal_error();
  735.  flag = no_interrupt(1);
  736.  errjmp_ok = 0;
  737.  gc_mark_and_sweep();
  738.  errjmp_ok = 1;
  739.  no_interrupt(flag);
  740.  if NULLP(freelist) gc_fatal_error();}
  741.  
  742. jmp_buf save_regs_gc_mark;
  743.  
  744. gc_mark_and_sweep()
  745. {LISP stack_end;
  746.  gc_ms_stats_start();
  747.  /* This assumes that all registers are saved into the jmp_buff */
  748.  setjmp(save_regs_gc_mark);
  749.  mark_locations((LISP *) save_regs_gc_mark,
  750.         (LISP *) ((char *) save_regs_gc_mark) + sizeof(save_regs_gc_mark));
  751.  mark_protected_registers();
  752.  mark_locations((LISP *) stack_start_ptr,
  753.         (LISP *) &stack_end);
  754. #if THINK_C
  755.  mark_locations((LISP *) ((char *) stack_start_ptr + 2),
  756.         (LISP *) ((char *) &stack_end + 2));
  757. #endif
  758.  gc_sweep();
  759.  gc_ms_stats_end();}
  760.  
  761. double gc_rt;
  762. long gc_cells_collected;
  763.  
  764. gc_ms_stats_start()
  765. {gc_rt = myruntime();
  766.  gc_cells_collected = 0;
  767.  if (gc_status_flag)
  768.    printf("[starting GC]\n");}
  769.  
  770. gc_ms_stats_end()
  771. {gc_rt = myruntime() - gc_rt;
  772.  gc_time_taken = gc_time_taken + gc_rt;
  773.  if (gc_status_flag)
  774.    printf("[GC took %g cpu seconds, %ld cells collected]\n",
  775.       gc_rt,
  776.       gc_cells_collected);}
  777.  
  778.  
  779. void gc_mark(ptr)
  780.      LISP ptr;
  781. {gc_mark_loop:
  782.  if NULLP(ptr) return;
  783.  if ((*ptr).gc_mark) return;
  784.  (*ptr).gc_mark = 1;
  785.  switch ((*ptr).type)
  786.    {case tc_flonum:
  787.       break;
  788.     case tc_cons:
  789.       gc_mark(CAR(ptr));
  790.       ptr = CDR(ptr);
  791.       goto gc_mark_loop;
  792.     case tc_symbol:
  793.       ptr = VCELL(ptr);
  794.       goto gc_mark_loop;
  795.     case tc_closure:
  796.       gc_mark((*ptr).storage_as.closure.code);
  797.       ptr = (*ptr).storage_as.closure.env;
  798.       goto gc_mark_loop;
  799.     case tc_subr_0:
  800.     case tc_subr_1:
  801.     case tc_subr_2:
  802.     case tc_subr_3:
  803.     case tc_lsubr:
  804.     case tc_fsubr:
  805.     case tc_msubr:
  806.       return;
  807.     case tc_user_1:
  808.     case tc_user_2:
  809.     case tc_user_3:
  810.     case tc_user_4:
  811.     case tc_user_5:
  812.       if (user_gc_mark != NULL)
  813.     {ptr = (*user_gc_mark)(ptr);
  814.      goto gc_mark_loop;}
  815.     default:
  816.       err("BUG IN GARBAGE COLLECTOR gc_mark",NIL);}}
  817.  
  818. mark_protected_registers()
  819. {struct gc_protected *reg;
  820.  LISP *location;
  821.  long j,n;
  822.  for(reg = protected_registers; reg; reg = (*reg).next)
  823.    {location = (*reg).location;
  824.     n = (*reg).length;
  825.     for(j=0;j<n;++j)
  826.       gc_mark(location[j]);}}
  827.  
  828. mark_locations(start,end)
  829.      LISP *start,*end;
  830. {LISP *tmp;
  831.  long n;
  832.  if (start > end)
  833.    {tmp = start;
  834.     start = end;
  835.     end = tmp;}
  836.  n = end - start;
  837.  mark_locations_array(start,n);}
  838.  
  839. mark_locations_array(x,n)
  840.      LISP x[];
  841.      long n;
  842. {int j;
  843.  LISP p;
  844.  for(j=0;j<n;++j)
  845.    {p = x[j];
  846.     if ((p >= heap_org) &&
  847.     (p < heap_end) &&
  848.     (((((char *)p) - ((char *)heap_org)) % sizeof(struct obj)) == 0) &&
  849.     NTYPEP(p,tc_free_cell))
  850.       gc_mark(p);}}
  851.  
  852.  
  853. gc_sweep()
  854. {LISP ptr,end,nfreelist;
  855.  long n;
  856.  end = heap_end;
  857.  n = 0;
  858.  nfreelist = freelist;
  859.  for(ptr=heap_org; ptr < end; ++ptr)
  860.    if (((*ptr).gc_mark == 0))
  861.      switch((*ptr).type)
  862.        {case tc_free_cell:
  863.       break;
  864.     case tc_user_1:
  865.     case tc_user_2:
  866.     case tc_user_3:
  867.     case tc_user_4:
  868.     case tc_user_5:
  869.       if (user_gc_free != NULL) (*user_gc_free)(ptr);
  870.     default:
  871.       ++n;
  872.       (*ptr).type = tc_free_cell;
  873.       CDR(ptr) = nfreelist;
  874.       nfreelist = ptr;}
  875.    else
  876.      (*ptr).gc_mark = 0;
  877.  gc_cells_collected = n;
  878.  freelist = nfreelist;}
  879.  
  880. LISP user_gc(args)
  881.      LISP args;
  882. {long old_status_flag,flag;
  883.  if (gc_kind_copying == 1)
  884.    err("implementation cannot GC at will with stop-and-copy\n",
  885.        NIL);
  886.  flag = no_interrupt(1);
  887.  errjmp_ok = 0;
  888.  old_status_flag = gc_status_flag;
  889.  if NNULLP(args)
  890.    if NULLP(car(args)) gc_status_flag = 0; else gc_status_flag = 1;
  891.  gc_mark_and_sweep();
  892.  gc_status_flag = old_status_flag;
  893.  errjmp_ok = 1;
  894.  no_interrupt(flag);
  895.  return(NIL);}
  896.  
  897. LISP gc_status(args)
  898.      LISP args;
  899. {LISP l;
  900.  int n;
  901.  if NNULLP(args) 
  902.    if NULLP(car(args)) gc_status_flag = 0; else gc_status_flag = 1;
  903.  if (gc_kind_copying == 1)
  904.    {if (gc_status_flag)
  905.       put_st("garbage collection is on\n");
  906.    else
  907.      put_st("garbage collection is off\n");
  908.     sprintf(tkbuffer,"%ld allocated %ld free\n",
  909.         heap - heap_org, heap_end - heap);
  910.     put_st(tkbuffer);}
  911.  else
  912.    {if (gc_status_flag)
  913.       put_st("garbage collection verbose\n");
  914.     else
  915.       put_st("garbage collection silent\n");
  916.     {for(n=0,l=freelist;NNULLP(l); ++n) l = CDR(l);
  917.      sprintf(tkbuffer,"%ld allocated %ld free\n",
  918.          (heap_end - heap_org) - n,n);
  919.      put_st(tkbuffer);}}
  920.  return(NIL);}
  921.  
  922. LISP leval_args(l,env)
  923.      LISP l,env;
  924. {LISP result,v1,v2,tmp;
  925.  if NULLP(l) return(NIL);
  926.  if NCONSP(l) err("bad syntax argument list",l);
  927.  result = cons(leval(CAR(l),env),NIL);
  928.  for(v1=result,v2=CDR(l);
  929.      CONSP(v2);
  930.      v1 = tmp, v2 = CDR(v2))
  931.   {tmp = cons(leval(CAR(v2),env),NIL);
  932.    CDR(v1) = tmp;}
  933.  if NNULLP(v2) err("bad syntax argument list",l);
  934.  return(result);}
  935.  
  936. LISP extend_env(actuals,formals,env)
  937.  LISP actuals,formals,env;
  938. {if SYMBOLP(formals)
  939.    return(cons(cons(cons(formals,NIL),cons(actuals,NIL)),env));
  940.  return(cons(cons(formals,actuals),env));}
  941.  
  942. LISP envlookup(var,env)
  943.  LISP var,env;
  944. {LISP frame,al,fl,tmp;
  945.  for(frame=env;CONSP(frame);frame=CDR(frame))
  946.    {tmp = CAR(frame);
  947.     if NCONSP(tmp) err("damaged frame",tmp);
  948.     for(fl=CAR(tmp),al=CDR(tmp);
  949.     CONSP(fl);
  950.     fl=CDR(fl),al=CDR(al))
  951.       {if NCONSP(al) err("too few arguments",tmp);
  952.        if EQ(CAR(fl),var) return(al);}}
  953.  if NNULLP(frame) err("damaged env",env);
  954.  return(NIL);}
  955.  
  956. LISP (*user_leval)() = NULL;
  957.  
  958. void set_eval_hooks(fcn)
  959.      LISP (*fcn)();
  960. {user_leval = fcn;}
  961.  
  962. LISP leval(x,env)
  963.  LISP x,env;
  964. {LISP tmp,arg1;
  965.  loop:
  966.  switch TYPE(x)
  967.    {case tc_symbol:
  968.       tmp = envlookup(x,env);
  969.       if NNULLP(tmp) return(CAR(tmp));
  970.       tmp = VCELL(x);
  971.       if EQ(tmp,unbound_marker) err("unbound variable",x);
  972.       return(tmp);
  973.     case tc_cons:
  974.       tmp = CAR(x);
  975.       switch TYPE(tmp)
  976.     {case tc_symbol:
  977.        tmp = envlookup(tmp,env);
  978.        if NNULLP(tmp)
  979.          {tmp = CAR(tmp);
  980.           break;}
  981.        tmp = VCELL(CAR(x));
  982.        if EQ(tmp,unbound_marker) err("unbound variable",CAR(x));
  983.        break;
  984.      case tc_cons:
  985.        tmp = leval(tmp,env);
  986.        break;}
  987.       switch TYPE(tmp)
  988.     {case tc_subr_0:
  989.        return(SUBRF(tmp)());
  990.      case tc_subr_1:
  991.        return(SUBRF(tmp)(leval(car(CDR(x)),env)));
  992.      case tc_subr_2:
  993.        x = CDR(x);
  994.        arg1 = leval(car(x),env);
  995.        x = NULLP(x) ? NIL : CDR(x);
  996.        return(SUBRF(tmp)(arg1,
  997.                  leval(car(x),env)));
  998.      case tc_subr_3:
  999.        x = CDR(x);
  1000.        arg1 = leval(car(x),env);
  1001.        x = NULLP(x) ? NIL : CDR(x);
  1002.        return(SUBRF(tmp)(arg1,
  1003.                  leval(car(x),env),
  1004.                  leval(car(cdr(x)),env)));
  1005.      case tc_lsubr:
  1006.        return(SUBRF(tmp)(leval_args(CDR(x),env)));
  1007.      case tc_fsubr:
  1008.        return(SUBRF(tmp)(CDR(x),env));
  1009.      case tc_msubr:
  1010.        if NULLP(SUBRF(tmp)(&x,&env)) return(x);
  1011.        goto loop;
  1012.      case tc_closure:
  1013.        env = extend_env(leval_args(CDR(x),env),
  1014.                 car((*tmp).storage_as.closure.code),
  1015.                 (*tmp).storage_as.closure.env);
  1016.        x = cdr((*tmp).storage_as.closure.code);
  1017.        goto loop;
  1018.      case tc_symbol:
  1019.        x = cons(tmp,cons(cons(sym_quote,cons(x,NIL)),NIL));
  1020.        x = leval(x,NIL);
  1021.        goto loop;
  1022.      case tc_user_1:
  1023.      case tc_user_2:
  1024.      case tc_user_3:
  1025.      case tc_user_4:
  1026.      case tc_user_5:
  1027.        if (user_leval != NULL)
  1028.          {if NULLP((*user_leval)(tmp,&x,&env)) return(x); else goto loop;}
  1029.      default:
  1030.        err("bad function",tmp);}
  1031.     default:
  1032.       return(x);}}
  1033.  
  1034. LISP setvar(var,val,env)
  1035.  LISP var,val,env;
  1036. {LISP tmp;
  1037.  if NSYMBOLP(var) err("wta(non-symbol) to setvar",var);
  1038.  tmp = envlookup(var,env);
  1039.  if NULLP(tmp) return(VCELL(var) = val);
  1040.  return(CAR(tmp)=val);}
  1041.  
  1042.  
  1043. LISP leval_setq(args,env)
  1044.  LISP args,env;
  1045. {return(setvar(car(args),leval(car(cdr(args)),env),env));}
  1046.  
  1047. LISP syntax_define(args)
  1048.  LISP args;
  1049. {if SYMBOLP(car(args)) return(args);
  1050.  return(syntax_define(
  1051.         cons(car(car(args)),
  1052.     cons(cons(sym_lambda,
  1053.          cons(cdr(car(args)),
  1054.           cdr(args))),
  1055.          NIL))));}
  1056.       
  1057. LISP leval_define(args,env)
  1058.  LISP args,env;
  1059. {LISP tmp,var,val;
  1060.  tmp = syntax_define(args);
  1061.  var = car(tmp);
  1062.  if NSYMBOLP(var) err("wta(non-symbol) to define",var);
  1063.  val = leval(car(cdr(tmp)),env);
  1064.  tmp = envlookup(var,env);
  1065.  if NNULLP(tmp) return(CAR(tmp) = val);
  1066.  if NULLP(env) return(VCELL(var) = val);
  1067.  tmp = car(env);
  1068.  setcar(tmp,cons(var,car(tmp)));
  1069.  setcdr(tmp,cons(val,cdr(tmp)));
  1070.  return(val);}
  1071.  
  1072. LISP leval_if(pform,penv)
  1073.  LISP *pform,*penv;
  1074. {LISP args,env;
  1075.  args = cdr(*pform);
  1076.  env = *penv;
  1077.  if NNULLP(leval(car(args),env)) 
  1078.     *pform = car(cdr(args)); else *pform = car(cdr(cdr(args)));
  1079.  return(truth);}
  1080.  
  1081. LISP leval_lambda(args,env)
  1082.  LISP args,env;
  1083. {LISP body;
  1084.  if NULLP(cdr(cdr(args)))
  1085.    body = car(cdr(args));
  1086.   else body = cons(sym_progn,cdr(args));
  1087.  return(closure(env,cons(arglchk(car(args)),body)));}
  1088.                          
  1089. LISP leval_progn(pform,penv)
  1090.  LISP *pform,*penv;
  1091. {LISP env,l,next;
  1092.  env = *penv;
  1093.  l = cdr(*pform);
  1094.  next = cdr(l);
  1095.  while(NNULLP(next)) {leval(car(l),env);l=next;next=cdr(next);}
  1096.  *pform = car(l); 
  1097.  return(truth);}
  1098.  
  1099. LISP leval_or(pform,penv)
  1100.  LISP *pform,*penv;
  1101. {LISP env,l,next,val;
  1102.  env = *penv;
  1103.  l = cdr(*pform);
  1104.  next = cdr(l);
  1105.  while(NNULLP(next))
  1106.    {val = leval(car(l),env);
  1107.     if NNULLP(val) {*pform = val; return(NIL);}
  1108.     l=next;next=cdr(next);}
  1109.  *pform = car(l); 
  1110.  return(truth);}
  1111.  
  1112. LISP leval_and(pform,penv)
  1113.  LISP *pform,*penv;
  1114. {LISP env,l,next;
  1115.  env = *penv;
  1116.  l = cdr(*pform);
  1117.  if NULLP(l) {*pform = truth; return(NIL);}
  1118.  next = cdr(l);
  1119.  while(NNULLP(next))
  1120.    {if NULLP(leval(car(l),env)) {*pform = NIL; return(NIL);}
  1121.     l=next;next=cdr(next);}
  1122.  *pform = car(l); 
  1123.  return(truth);}
  1124.  
  1125. LISP leval_catch(args,env)
  1126.  LISP args,env;
  1127. {struct catch_frame frame;
  1128.  int k;
  1129.  LISP l,val;
  1130.  frame.tag = leval(car(args),env);
  1131.  frame.next = catch_framep;
  1132.  k = setjmp(frame.cframe);
  1133.  catch_framep = &frame;
  1134.  if (k == 2)
  1135.    {catch_framep = frame.next;
  1136.     return(frame.retval);}
  1137.  for(l=cdr(args); NNULLP(l); l = cdr(l))
  1138.    val = leval(car(l),env);
  1139.  catch_framep = frame.next;
  1140.  return(val);}
  1141.  
  1142. LISP lthrow(tag,value)
  1143.      LISP tag,value;
  1144. {struct catch_frame *l;
  1145.  for(l=catch_framep; l; l = (*l).next)
  1146.    if EQ((*l).tag,tag)
  1147.      {(*l).retval = value;
  1148.       longjmp((*l).cframe,2);}
  1149.  err("no *catch found with this tag",tag);
  1150.  return(NIL);}
  1151.  
  1152. LISP leval_let(pform,penv)
  1153.  LISP *pform,*penv;
  1154. {LISP env,l;
  1155.  l = cdr(*pform);
  1156.  env = *penv;
  1157.  *penv = extend_env(leval_args(car(cdr(l)),env),car(l),env);
  1158.  *pform = car(cdr(cdr(l)));
  1159.  return(truth);}
  1160.  
  1161. LISP reverse(l)
  1162.  LISP l;
  1163. {LISP n,p;
  1164.  n = NIL;
  1165.  for(p=l;NNULLP(p);p=cdr(p)) n = cons(car(p),n);
  1166.  return(n);}
  1167.  
  1168. LISP let_macro(form)
  1169.  LISP form;
  1170. {LISP p,fl,al,tmp;
  1171.  fl = NIL;
  1172.  al = NIL;
  1173.  for(p=car(cdr(form));NNULLP(p);p=cdr(p))
  1174.   {tmp = car(p);
  1175.    if SYMBOLP(tmp) {fl = cons(tmp,fl); al = cons(NIL,al);}
  1176.    else {fl = cons(car(tmp),fl); al = cons(car(cdr(tmp)),al);}}
  1177.  p = cdr(cdr(form));
  1178.  if NULLP(cdr(p)) p = car(p); else p = cons(sym_progn,p);
  1179.  setcdr(form,cons(reverse(fl),cons(reverse(al),cons(p,NIL))));
  1180.  setcar(form,cintern("let-internal"));
  1181.  return(form);}
  1182.    
  1183.  LISP leval_quote(args,env)
  1184.  LISP args,env;
  1185. {return(car(args));}
  1186.  
  1187. LISP leval_tenv(args,env)
  1188.  LISP args,env;
  1189. {return(env);}
  1190.  
  1191. LISP symbolconc(args)
  1192.      LISP args;
  1193. {long size;
  1194.  LISP l,s;
  1195.  size = 0;
  1196.  tkbuffer[0] = 0;
  1197.  for(l=args;NNULLP(l);l=cdr(l))
  1198.    {s = car(l);
  1199.     if NSYMBOLP(s) err("wta(non-symbol) to symbolconc",s);
  1200.     size = size + strlen(PNAME(s));
  1201.     if (size >  TKBUFFERN) err("symbolconc buffer overflow",NIL);
  1202.     strcat(tkbuffer,PNAME(s));}
  1203.  return(rintern(tkbuffer));}
  1204.  
  1205.  
  1206. void (*user_prin1)() = NULL;
  1207.  
  1208. void set_print_hooks(fcn)
  1209.      void (*fcn)();
  1210. {user_prin1 = fcn;}
  1211.  
  1212. LISP lprin1f(exp,f)
  1213.      LISP exp;
  1214.      FILE *f;
  1215. {LISP tmp;
  1216.  switch TYPE(exp)
  1217.    {case tc_nil:
  1218.       fput_st(f,"()");
  1219.       break;
  1220.    case tc_cons:
  1221.       fput_st(f,"(");
  1222.       lprin1f(car(exp),f);
  1223.       for(tmp=cdr(exp);CONSP(tmp);tmp=cdr(tmp))
  1224.     {fput_st(f," ");lprin1f(car(tmp),f);}
  1225.       if NNULLP(tmp) {fput_st(f," . ");lprin1f(tmp,f);}
  1226.       fput_st(f,")");
  1227.       break;
  1228.     case tc_flonum:
  1229.       sprintf(tkbuffer,"%g",FLONM(exp));
  1230.       fput_st(f,tkbuffer);
  1231.       break;
  1232.     case tc_symbol:
  1233.       fput_st(f,PNAME(exp));
  1234.       break;
  1235.     case tc_subr_0:
  1236.     case tc_subr_1:
  1237.     case tc_subr_2:
  1238.     case tc_subr_3:
  1239.     case tc_lsubr:
  1240.     case tc_fsubr:
  1241.     case tc_msubr:
  1242.       sprintf(tkbuffer,"#<SUBR(%d) ",TYPE(exp));
  1243.       fput_st(f,tkbuffer);
  1244.       fput_st(f,(*exp).storage_as.subr.name);
  1245.       fput_st(f,">");
  1246.       break;
  1247.     case tc_closure:
  1248.       fput_st(f,"#<CLOSURE ");
  1249.       lprin1f(car((*exp).storage_as.closure.code),f);
  1250.       fput_st(f," ");
  1251.       lprin1f(cdr((*exp).storage_as.closure.code),f);
  1252.       fput_st(f,">");
  1253.       break;
  1254.     case tc_user_1:
  1255.     case tc_user_2:
  1256.     case tc_user_3:
  1257.     case tc_user_4:
  1258.     case tc_user_5:
  1259.       if (user_prin1 != NULL)
  1260.     {(*user_prin1)(exp,f);
  1261.      break;}
  1262.     default:
  1263.       sprintf(tkbuffer,"#<UNKNOWN %d %lX>",TYPE(exp),exp);
  1264.       fput_st(f,tkbuffer);}
  1265.  return(NIL);}
  1266.  
  1267. LISP lprint(exp)
  1268.  LISP exp;
  1269. {lprin1f(exp,stdout);
  1270.  put_st("\n");
  1271.  return(NIL);}
  1272.  
  1273. LISP lreadr(),lreadparen(),lreadtk(),lreadf();
  1274.  
  1275. LISP lread()
  1276. {return(lreadf(stdin));}
  1277.  
  1278. int f_getc(f)
  1279.      FILE *f;
  1280. {long iflag,dflag;
  1281.  int c;
  1282.  iflag = no_interrupt(1);
  1283.  dflag = interrupt_differed;
  1284.  c = getc(f);
  1285. #ifdef VMS
  1286.  if ((dflag == 0) & interrupt_differed & (f == stdin))
  1287.    while((c != 0) & (c != EOF)) c = getc(f);
  1288. #endif
  1289.  no_interrupt(iflag);
  1290.  return(c);}
  1291.  
  1292. void f_ungetc(c,f)
  1293.      int c; FILE *f;
  1294. {ungetc(c,f);}
  1295.  
  1296.  int
  1297. flush_ws(f,eoferr)
  1298.  struct gen_readio *f;
  1299.  char *eoferr;
  1300. {int c,commentp;
  1301.  commentp = 0;
  1302.  while(1)
  1303.    {c = GETC_FCN(f);
  1304.     if (c == EOF) if (eoferr) err(eoferr,NIL); else return(c);
  1305.     if (commentp) {if (c == '\n') commentp = 0;}
  1306.     else if (c == ';') commentp = 1;
  1307.     else if (!isspace(c)) return(c);}}
  1308.  
  1309. LISP lreadf(f)
  1310.      FILE *f;
  1311. {return(gen_read(f_getc,f_ungetc,f));}
  1312.  
  1313. LISP readtl(f)
  1314.   struct gen_readio *f;
  1315. {int c;
  1316.  c = flush_ws(f,(char *)NULL);
  1317.  if (c == EOF) return(eof_val);
  1318.  UNGETC_FCN(c,f);
  1319.  return(lreadr(f));}
  1320.  
  1321. LISP gen_read(f1,f2,x)
  1322.      int (*f1)();
  1323.      void (*f2)();
  1324.      char *x;
  1325. {struct gen_readio f;
  1326.  f.getc_fcn = f1;
  1327.  f.ungetc_fcn = f2;
  1328.  f.cb_argument = x;
  1329.  return(readtl(&f));}
  1330.  
  1331. char *user_ch_readm = "";
  1332. char *user_te_readm = "";
  1333.  
  1334. LISP (*user_readm)() = NULL;
  1335. LISP (*user_readt)() = NULL;
  1336.  
  1337. void set_read_hooks(all_set,end_set,fcn1,fcn2)
  1338.      char *all_set,*end_set;
  1339.      LISP (*fcn1)(),(*fcn2)();
  1340. {user_ch_readm = all_set;
  1341.  user_te_readm = end_set;
  1342.  user_readm = fcn1;
  1343.  user_readt = fcn2;}
  1344.  
  1345. LISP lreadr(f)
  1346.  struct gen_readio *f;
  1347. {int c,j;
  1348.  char *p;
  1349.  c = flush_ws(f,"end of file inside read");
  1350.  switch (c)
  1351.    {case '(':
  1352.       return(lreadparen(f));
  1353.     case ')':
  1354.       err("unexpected close paren",NIL);
  1355.     case '\'':
  1356.       return(cons(sym_quote,cons(lreadr(f),NIL)));
  1357.     case '`':
  1358.       return(cons(cintern("+internal-backquote"),lreadr(f)));
  1359.     case ',':
  1360.       c = GETC_FCN(f);
  1361.       switch(c)
  1362.     {case '@':
  1363.        p = "+internal-comma-atsign";
  1364.        break;
  1365.      case '.':
  1366.        p = "+internal-comma-dot";
  1367.        break;
  1368.      default:
  1369.        p = "+internal-comma";
  1370.        UNGETC_FCN(c,f);}
  1371.       return(cons(cintern(p),lreadr(f)));
  1372.     default:
  1373.       if ((user_readm != NULL) && strchr(user_ch_readm,c))
  1374.     return((*user_readm)(c,f));}
  1375.  p = tkbuffer;
  1376.  *p++ = c;
  1377.  for(j = 1; j<TKBUFFERN; ++j)
  1378.    {c = GETC_FCN(f);
  1379.     if (c == EOF) return(lreadtk(j));
  1380.     if (isspace(c)) return(lreadtk(j));
  1381.     if (strchr("()'`,;",c) || strchr(user_te_readm,c))
  1382.       {UNGETC_FCN(c,f);return(lreadtk(j));}
  1383.     *p++ = c;}
  1384.  err("token larger than TKBUFFERN",NIL);}
  1385.  
  1386. LISP lreadparen(f)
  1387.  struct gen_readio *f;
  1388. {int c;
  1389.  LISP tmp;
  1390.  c = flush_ws(f,"end of file inside list");
  1391.  if (c == ')') return(NIL);
  1392.  UNGETC_FCN(c,f);
  1393.  tmp = lreadr(f);
  1394.  if EQ(tmp,sym_dot)
  1395.    {tmp = lreadr(f);
  1396.     c = flush_ws(f,"end of file inside list");
  1397.     if (c != ')') err("missing close paren",NIL);
  1398.     return(tmp);}
  1399.  return(cons(tmp,lreadparen(f)));}
  1400.  
  1401.  
  1402.  
  1403. LISP lreadtk(j)
  1404.      long j;
  1405. {int k,flag;
  1406.  char c,*p;
  1407.  LISP tmp;
  1408.  int adigit;
  1409.  p = tkbuffer;
  1410.  p[j] = 0;
  1411.  if (user_readt != NULL)
  1412.    {tmp = (*user_readt)(p,j,&flag);
  1413.     if (flag) return(tmp);}
  1414.  if (*p == '-') p+=1;
  1415.  adigit = 0;
  1416.  while(isdigit(*p)) {p+=1; adigit=1;}
  1417.  if (*p=='.')
  1418.    {p += 1;
  1419.     while(isdigit(*p)) {p+=1; adigit=1;}}
  1420.  if (!adigit) goto a_symbol;
  1421.  if (*p=='e')
  1422.    {p+=1;
  1423.     if (*p=='-'||*p=='+') p+=1;
  1424.     if (!isdigit(*p)) goto a_symbol; else p+=1;
  1425.     while(isdigit(*p)) p+=1;}
  1426.  if (*p) goto a_symbol;
  1427.  return(flocons(atof(tkbuffer)));
  1428.  a_symbol:
  1429.  return(rintern(tkbuffer));}
  1430.       
  1431. LISP copy_list(x)
  1432.  LISP x;
  1433. {if NULLP(x) return(NIL);
  1434.  return(cons(car(x),copy_list(cdr(x))));}
  1435.  
  1436. LISP oblistfn()
  1437. {return(copy_list(oblistvar));}
  1438.  
  1439. close_open_files()
  1440. {LISP l;
  1441.  FILE *p;
  1442.  for(l=open_files;NNULLP(l);l=cdr(l))
  1443.    {p = (FILE *) PNAME(car(l));
  1444.     if (p)
  1445.       {printf("closing a file left open\n");
  1446.        fclose(p);}}
  1447.  open_files = NIL;}
  1448.  
  1449. FILE *fopen_care(name,how)
  1450.      char *name,*how;
  1451. {FILE *f;
  1452.  LISP sym;
  1453.  long flag;
  1454.  sym = symcons(0,NIL);
  1455.  open_files = cons(sym,open_files);
  1456.  flag = no_interrupt(1);
  1457.  f = fopen(name,how);
  1458.  if (!f)
  1459.    {perror(name);
  1460.     err("could not open file",NIL);}
  1461.  PNAME(sym) = (char *) f;
  1462.  no_interrupt(flag);
  1463.  return(f);}
  1464.  
  1465. LISP fclose_dq(f,l)
  1466.      FILE *f;
  1467.      LISP l;
  1468. {FILE *p;
  1469.  if NULLP(l) return(l);
  1470.  if (PNAME(CAR(l)) == (char *) f) return(CDR(l));
  1471.  CDR(l) = fclose_dq(f,CDR(l));
  1472.  return(l);}
  1473.  
  1474.  
  1475. fclose_care(f)
  1476.      FILE *f;
  1477. {long flag;
  1478.  LISP l;
  1479.  flag = no_interrupt(1);
  1480.  fclose(f);
  1481.  open_files = fclose_dq(f,open_files);
  1482.  no_interrupt(flag);}
  1483.  
  1484. LISP vload(fname,cflag)
  1485.      char *fname;
  1486.      long cflag;
  1487. {LISP form,result,tail;
  1488.  FILE *f;
  1489.  put_st("loading ");
  1490.  put_st(fname);
  1491.  put_st("\n");
  1492.  f = fopen_care(fname,"r");
  1493.  result = NIL;
  1494.  tail = NIL;
  1495.  while(1)
  1496.    {form = lreadf(f);
  1497.     if EQ(form,eof_val) break;
  1498.     if (cflag)
  1499.       {form = cons(form,NIL);
  1500.        if NULLP(result)
  1501.      result = tail = form;
  1502.        else
  1503.      tail = setcdr(tail,form);}
  1504.     else
  1505.       leval(form,NIL);}
  1506.  fclose_care(f);
  1507.  put_st("done.\n");
  1508.  return(result);}
  1509.  
  1510. LISP load(fname,cflag)
  1511.  LISP fname,cflag;
  1512. {if NSYMBOLP(fname) err("filename not a symbol",fname);
  1513.  return(vload(PNAME(fname),NULLP(cflag) ? 0 : 1));}
  1514.  
  1515. LISP save_forms(fname,forms,how)
  1516.      LISP fname,forms,how;
  1517. {char *cname,*chow;
  1518.  LISP l;
  1519.  FILE *f;
  1520.  if NSYMBOLP(fname) err("filename not a symbol",fname);
  1521.  cname = PNAME(fname);
  1522.  if EQ(how,NIL) chow = "w";
  1523.  else if EQ(how,cintern("a")) chow = "a";
  1524.  else err("bad argument to save-forms",how);
  1525.  put_st((*chow == 'a') ? "appending" : "saving");
  1526.  put_st(" forms to ");
  1527.  put_st(cname);
  1528.  put_st("\n");
  1529.  f = fopen_care(cname,chow);
  1530.  for(l=forms;NNULLP(l);l=cdr(l))
  1531.    {lprin1f(car(l),f);
  1532.     putc('\n',f);}
  1533.  fclose_care(f);
  1534.  put_st("done.\n");
  1535.  return(truth);}
  1536.  
  1537. LISP quit()
  1538. {longjmp(errjmp,2);
  1539.  return(NIL);}
  1540.  
  1541. LISP nullp(x)
  1542.  LISP x;
  1543. {if EQ(x,NIL) return(truth); else return(NIL);}
  1544.  
  1545. LISP arglchk(x)
  1546.  LISP x;
  1547. {LISP l;
  1548.  if SYMBOLP(x) return(x);
  1549.  for(l=x;CONSP(l);l=CDR(l));
  1550.  if NNULLP(l) err("improper formal argument list",x);
  1551.  return(x);}
  1552.  
  1553.  
  1554. init_subrs()
  1555. {init_subr("cons",tc_subr_2,cons);
  1556.  init_subr("car",tc_subr_1,car);
  1557.  init_subr("cdr",tc_subr_1,cdr);
  1558.  init_subr("set-car!",tc_subr_2,setcar);
  1559.  init_subr("set-cdr!",tc_subr_2,setcdr);
  1560.  init_subr("+",tc_subr_2,plus);
  1561.  init_subr("-",tc_subr_2,difference);
  1562.  init_subr("*",tc_subr_2,ltimes);
  1563.  init_subr("/",tc_subr_2,quotient);
  1564.  init_subr(">",tc_subr_2,greaterp);
  1565.  init_subr("<",tc_subr_2,lessp);
  1566.  init_subr("eq?",tc_subr_2,eq);
  1567.  init_subr("eqv?",tc_subr_2,eql);
  1568.  init_subr("assq",tc_subr_2,assq);
  1569.  init_subr("read",tc_subr_0,lread);
  1570.  init_subr("eof-val",tc_subr_0,get_eof_val);
  1571.  init_subr("print",tc_subr_1,lprint);
  1572.  init_subr("eval",tc_subr_2,leval);
  1573.  init_subr("define",tc_fsubr,leval_define);
  1574.  init_subr("lambda",tc_fsubr,leval_lambda);
  1575.  init_subr("if",tc_msubr,leval_if);
  1576.  init_subr("begin",tc_msubr,leval_progn);
  1577.  init_subr("set!",tc_fsubr,leval_setq);
  1578.  init_subr("or",tc_msubr,leval_or);
  1579.  init_subr("and",tc_msubr,leval_and);
  1580.  init_subr("*catch",tc_fsubr,leval_catch);
  1581.  init_subr("*throw",tc_subr_2,lthrow);
  1582.  init_subr("quote",tc_fsubr,leval_quote);
  1583.  init_subr("oblist",tc_subr_0,oblistfn);
  1584.  init_subr("copy-list",tc_subr_1,copy_list);
  1585.  init_subr("gc-status",tc_lsubr,gc_status);
  1586.  init_subr("gc",tc_lsubr,user_gc);
  1587.  init_subr("load",tc_subr_2,load);
  1588.  init_subr("pair?",tc_subr_1,consp);
  1589.  init_subr("symbol?",tc_subr_1,symbolp);
  1590.  init_subr("number?",tc_subr_1,numberp);
  1591.  init_subr("let-internal",tc_msubr,leval_let);
  1592.  init_subr("let-internal-macro",tc_subr_1,let_macro);
  1593.  init_subr("symbol-bound?",tc_subr_2,symbol_boundp);
  1594.  init_subr("symbol-value",tc_subr_2,symbol_value);
  1595.  init_subr("set-symbol-value!",tc_subr_3,setvar);
  1596.  init_subr("the-environment",tc_fsubr,leval_tenv);
  1597.  init_subr("error",tc_subr_2,lerr);
  1598.  init_subr("quit",tc_subr_0,quit);
  1599.  init_subr("not",tc_subr_1,nullp);
  1600.  init_subr("null?",tc_subr_1,nullp);
  1601.  init_subr("env-lookup",tc_subr_2,envlookup);
  1602.  init_subr("reverse",tc_subr_1,reverse);
  1603.  init_subr("symbolconc",tc_lsubr,symbolconc);
  1604.  init_subr("save-forms",tc_subr_3,save_forms);}
  1605.  
  1606.